﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace CubeMeasure
{
    /// <summary>
    /// Klasse für das Measurement - tool
    /// </summary>
    public partial class CubeMeasureMain : DigitalRune.Windows.Docking.DockableForm
    {
        [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
        static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

        [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
        static extern IntPtr GetMessageExtraInfo();

        private enum InputType
        {
            INPUT_MOUSE = 0,
            INPUT_KEYBOARD = 1,
            INPUT_HARDWARE = 2,
        }

        [Flags()]
        private enum MOUSEEVENTF
        {
            MOVE = 0x0001,  // mouse move 
            LEFTDOWN = 0x0002,  // left button down
            LEFTUP = 0x0004,  // left button up
            RIGHTDOWN = 0x0008,  // right button down
            RIGHTUP = 0x0010,  // right button up
            MIDDLEDOWN = 0x0020,  // middle button down
            MIDDLEUP = 0x0040,  // middle button up
            XDOWN = 0x0080,  // x button down 
            XUP = 0x0100,  // x button down
            WHEEL = 0x0800,  // wheel button rolled
            VIRTUALDESK = 0x4000,  // map to entire virtual desktop
            ABSOLUTE = 0x8000,  // absolute move
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public int mouseData;
            public MOUSEEVENTF dwFlags;
            public int time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct INPUT
        {
            public InputType type;
            public MOUSEINPUT mi;
        }
        /// <summary>
        /// Konstruktor
        /// </summary>
        public CubeMeasureMain()
        {
            InitializeComponent();
           
            cadControl.SaveMeasure += new EventHandler<SimpleCADControl.MeasureEventArgs>(cadControl_SaveMeasure);
        }



        /// <summary>
        /// Fügt ein GeoObject zum CadControl hinzu
        /// </summary>
        /// <param name="geoObject">GeoObject</param>
        public void AddGeoObject(SimpleCADControl.GeoObjects.GeoObject geoObject)
        {
            cadControl.Add(geoObject);
            this.Focus();
        }

        /// <summary>
        /// Gibt alle GeoObject zurück
        /// </summary>
        /// <returns>GeoObjects - Liste</returns>
        public List<SimpleCADControl.GeoObjects.GeoObject> GetGeoObjects()
        {
            return cadControl.GeoObjects;
        }


        /// <summary>
        /// Gibt ein bestimmtes GeoObject zurück
        /// </summary>
        /// <param name="number">Nummer des GeoObjects</param>
        /// <returns>Ein GeoObject</returns>
        public SimpleCADControl.GeoObjects.GeoObject GetGeoObject(int number)
        {
            return cadControl.GeoObjects[number];
        }


        /// <summary>
        /// Speichert die gemessenen Daten in einer Liste
        /// </summary>
        /// <param name="sender">this</param>
        /// <param name="e">EventArgs</param>
        void cadControl_SaveMeasure(object sender, SimpleCADControl.MeasureEventArgs e)
        {
            ListViewItem itm = new ListViewItem(new String[] { (listViewMeasuredData.Items.Count + 1).ToString(), e.StartPoint.X.ToString(), e.StartPoint.Y.ToString(), e.EndPoint.X.ToString(), e.EndPoint.Y.ToString(), e.Distance.ToString() });
            itm.BackColor = listViewMeasuredData.Items.Count % 2 == 0 ? Color.Beige : Color.White; //Einfärben der Zeilen
            
            itm.ImageIndex = 0;
            listViewMeasuredData.Items.Add(itm);
        }


        /// <summary>
        /// Wird aufgerufen, wenn das Fenster geschlossen wird, verhindert das Schließen und minimiert das Fenster
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CubeMeasureMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                this.Hide();
            }

        }


        /// <summary>
        /// Löscht Messdaten aus der Liste
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach(ListViewItem itm in listViewMeasuredData.SelectedItems)
            {
                listViewMeasuredData.Items.Remove(itm);
            }
            ResetIndices();
        }



        /// <summary>
        /// Reinitialisiert die indizes, falls ein Element gelöscht wurde etc.
        /// </summary>
        private void ResetIndices()
        {
            int i = 1;
            foreach (ListViewItem itm in listViewMeasuredData.Items)
            {
                itm.SubItems[0].Text = (i++).ToString();
                itm.BackColor = i % 2 == 0 ? Color.Beige : Color.White;
            }
        }



        /// <summary>
        /// Fängt Tastaturkommandos ab
        /// </summary>
        /// <param name="msg">Nachricht</param>
        /// <param name="keyData">Tastaturkommando</param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            //Maus mit Cursortasten steuern:
            if (keyData == Keys.Up)
            {
                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - 1); 
            }

            if (keyData == Keys.Down)
            {
                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 1);
            }
            if (keyData == Keys.Left)
            {
                Cursor.Position = new Point(Cursor.Position.X - 1, Cursor.Position.Y);
            }

            if (keyData == Keys.Right)
            {
                Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y);
            }


            if (keyData == Keys.Space)
            {
                SimulateMouseClick();
            }

            //Löscht ein Element aus der Liste
            if (keyData == Keys.Delete)
            {
                foreach (ListViewItem itm in listViewMeasuredData.SelectedItems)
                {
                    listViewMeasuredData.Items.Remove(itm);
                }
                ResetIndices();
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }



        /// <summary>
        /// Simuliert mit Hilfe von COM einen Mausklick
        /// </summary>
        /// <returns></returns>
        private static uint SimulateMouseClick()
        {
            INPUT input_down = new INPUT();
            input_down.type = InputType.INPUT_MOUSE;

            input_down.mi.dx = 0;
            input_down.mi.dy = 0;
            input_down.mi.mouseData = 0;
            input_down.mi.dwFlags = MOUSEEVENTF.LEFTDOWN;
            input_down.mi.time = 0;
            input_down.mi.dwExtraInfo = GetMessageExtraInfo();

            INPUT input_up = input_down;
            input_up.mi.dwFlags = MOUSEEVENTF.LEFTUP;

            INPUT[] input = { input_down, input_up };
            return SendInput(2, input, Marshal.SizeOf(input_down));
        }

        /// <summary>
        /// Speichert die Messdaten in einer CSV-Datei
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                using (StreamWriter writer = new StreamWriter(new FileStream(saveFileDialog.FileName, FileMode.Create)))
                {
                    foreach (ListViewItem itm in listViewMeasuredData.Items)
                    {
                        writer.WriteLine(itm.SubItems[1].Text + ";" +
                            itm.SubItems[2].Text + ";" +
                            itm.SubItems[3].Text + ";" +
                            itm.SubItems[4].Text + ";" +
                            itm.SubItems[5].Text);
                    }
                    writer.Flush();
                    writer.Close();
                }
            }
        }


        /// <summary>
        /// Speichert nur die markierten Messdaten in einer CSV-Datei
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonSaveSelected_Click(object sender, EventArgs e)
        {
            if (listViewMeasuredData.SelectedItems.Count <= 0)
            {
                return;
            }

            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                using (StreamWriter writer = new StreamWriter(new FileStream(saveFileDialog.FileName, FileMode.Create)))
                {
                    foreach (ListViewItem itm in listViewMeasuredData.SelectedItems)
                    {
                        writer.WriteLine(itm.SubItems[1].Text + ";" +
                            itm.SubItems[2].Text + ";" +
                            itm.SubItems[3].Text + ";" +
                            itm.SubItems[4].Text + ";" +
                            itm.SubItems[5].Text);
                    }
                    writer.Flush();
                    writer.Close();
                }
            }
        }


        /// <summary>
        /// alle Messdaten löschen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripButtonNewMeasure_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Delete measure data?", "Delete?", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == System.Windows.Forms.DialogResult.Yes)
            {
                listViewMeasuredData.Items.Clear();
            }
        }
    }
}
